package com.ruoyi.system.service.impl;

import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import com.ruoyi.common.utils.StringUtils;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.system.domain.BizDeliveryBatch;
import com.ruoyi.system.mapper.BizDeliveryNoteMapper;
import com.ruoyi.system.domain.BizDeliveryNote;
import com.ruoyi.system.service.IBizDeliveryNoteService;
import com.ruoyi.system.domain.BizDeliveryBarcode;
import com.ruoyi.system.mapper.BizDeliveryBarcodeMapper;
import com.ruoyi.system.mapper.BizBarcodeMapper;
import com.ruoyi.system.domain.BizBarcode;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * 送货单Service业务层处理
 * 
 * @author ruoyi
 * @date 2025-10-22
 */
@Service
public class BizDeliveryNoteServiceImpl implements IBizDeliveryNoteService 
{
    @Autowired
    private BizDeliveryNoteMapper bizDeliveryNoteMapper;

    @Autowired
    private BizDeliveryBarcodeMapper bizDeliveryBarcodeMapper;

    @Autowired
    private BizBarcodeMapper bizBarcodeMapper;

    /**
     * 查询送货单
     * 
     * @param deliveryNoteId 送货单主键
     * @return 送货单
     */
    @Override
    public BizDeliveryNote selectBizDeliveryNoteByDeliveryNoteId(Long deliveryNoteId)
    {
        return bizDeliveryNoteMapper.selectBizDeliveryNoteByDeliveryNoteId(deliveryNoteId);
    }

    /**
     * 查询送货单列表
     * 
     * @param bizDeliveryNote 送货单
     * @return 送货单
     */
    @Override
    public List<BizDeliveryNote> selectBizDeliveryNoteList(BizDeliveryNote bizDeliveryNote)
    {
        return bizDeliveryNoteMapper.selectBizDeliveryNoteList(bizDeliveryNote);
    }

    /**
     * 新增送货单
     * 
     * @param bizDeliveryNote 送货单
     * @return 结果
     */
    @Transactional
    @Override
    public int insertBizDeliveryNote(BizDeliveryNote bizDeliveryNote)
    {
        // 1) 生成送货单编号 DNyyyyMMddNNN
        String today = DateUtils.parseDateToStr("yyyyMMdd", DateUtils.getNowDate());
        String prefix = "DN" + today;
        String maxNo = bizDeliveryNoteMapper.selectMaxDeliveryNoteNoByDate(prefix);
        int seq = 1;
        if (StringUtils.isNotEmpty(maxNo) && maxNo.length() >= prefix.length() + 3) {
            String s = maxNo.substring(prefix.length());
            try { seq = Integer.parseInt(s) + 1; } catch (Exception ignore) { seq = 1; }
        }
        String nextNo = prefix + String.format("%03d", seq);
        bizDeliveryNote.setDeliveryNoteNo(nextNo);

        // 2) 送货状态、创建人、创建时间
        bizDeliveryNote.setDeliveryStatus("CREATED");
        bizDeliveryNote.setCreatedBy(SecurityUtils.getUsername());
        bizDeliveryNote.setCreatedTime(DateUtils.getNowDate());

        // 3) 计算总箱数与总数量，并填充批次的送货单编号/状态/创建元数据
        Long totalBoxes = 0L;
        BigDecimal totalQuantity = BigDecimal.ZERO;
        List<BizDeliveryBatch> bizDeliveryBatchList = bizDeliveryNote.getBizDeliveryBatchList();
        if (StringUtils.isNotNull(bizDeliveryBatchList)) {
            for (BizDeliveryBatch b : bizDeliveryBatchList) {
                if (b.getBatchBoxes() != null) {
                    totalBoxes += b.getBatchBoxes();
                }
                if (b.getBatchQuantity() != null) {
                    totalQuantity = totalQuantity.add(b.getBatchQuantity());
                }
                b.setDeliveryNoteNo(nextNo);
                b.setBatchStatus("PENDING");
                b.setCreatedBy(SecurityUtils.getUsername());
                b.setCreatedTime(DateUtils.getNowDate());
            }
        }
        bizDeliveryNote.setTotalBoxes(totalBoxes);
        bizDeliveryNote.setTotalQuantity(totalQuantity);

        // 4) 插入主表，获取 deliveryNoteId
        int rows = bizDeliveryNoteMapper.insertBizDeliveryNote(bizDeliveryNote);

        // 5) 插入批次明细（方法内会设置 deliveryNoteId）
        insertBizDeliveryBatch(bizDeliveryNote);

        // 6) 批次插入后回查对应批次ID，建立 (batchNo,itemId)->deliveryBatchId 映射
        Map<String, Long> batchKeyToId = new HashMap<>();
        List<BizDeliveryBatch> persistedBatches = bizDeliveryNoteMapper.selectBizDeliveryBatchListByNoteId(bizDeliveryNote.getDeliveryNoteId());
        if (persistedBatches != null) {
            for (BizDeliveryBatch pb : persistedBatches) {
                String key = (pb.getBatchNo() == null ? "" : pb.getBatchNo()) + "#" + (pb.getItemId() == null ? "" : pb.getItemId());
                batchKeyToId.put(key, pb.getDeliveryBatchId());
            }
        }

        // 7) 组装箱码关联数据并批量插入
        List<BizDeliveryBarcode> barcodeList = bizDeliveryNote.getBizDeliveryBarcodeList();
        if (StringUtils.isNotNull(barcodeList) && !barcodeList.isEmpty()) {
            List<BizDeliveryBarcode> toInsert = new ArrayList<>();
            for (BizDeliveryBarcode src : barcodeList) {
                // 通过 barcodeId 反查箱码，拿到 batchNo 与 itemId，匹配批次ID
                BizBarcode bc = null;
                if (src.getBarcodeId() != null) {
                    bc = bizBarcodeMapper.selectBizBarcodeByBarcodeId(src.getBarcodeId());
                }
                Long deliveryBatchId = null;
                if (bc != null) {
                    String key = (bc.getBatchNo() == null ? "" : bc.getBatchNo()) + "#" + (bc.getItemId() == null ? "" : bc.getItemId());
                    deliveryBatchId = batchKeyToId.get(key);
                }

                BizDeliveryBarcode item = new BizDeliveryBarcode();
                item.setDeliveryBatchId(deliveryBatchId);
                item.setDeliveryNoteId(bizDeliveryNote.getDeliveryNoteId());
                item.setBarcodeId(src.getBarcodeId());
                item.setBarcode(src.getBarcode());
                // 优先使用箱码表反查到的权威字段
                item.setInventoryCode(bc != null ? bc.getInventoryCode() : src.getInventoryCode());
                item.setPackQuantity(bc != null ? bc.getPackQuantity() : src.getPackQuantity());
                item.setUnitCode(bc != null ? bc.getUnitCode() : src.getUnitCode());
                item.setBarcodeStatus("PENDING");
                item.setCreateBy(SecurityUtils.getUsername());
                item.setCreateTime(DateUtils.getNowDate());
                toInsert.add(item);
            }

            // 校验所有箱码均能映射到批次；若存在无法映射的情况，仍插入但 delivery_batch_id 为空会违反非空约束，主动抛错更安全
            for (BizDeliveryBarcode item : toInsert) {
                if (item.getDeliveryBatchId() == null) {
                    throw new RuntimeException("箱码与批次匹配失败: barcodeId=" + item.getBarcodeId());
                }
            }

            bizDeliveryBarcodeMapper.batchInsertBizDeliveryBarcode(toInsert);

            // 8) 同步更新主条码状态为 DELIVERED，并写入送货单号与送货时间
            java.util.List<Long> barcodeIds = new java.util.ArrayList<>();
            for (BizDeliveryBarcode item : toInsert) {
                if (item.getBarcodeId() != null) {
                    barcodeIds.add(item.getBarcodeId());
                }
            }
            if (!barcodeIds.isEmpty()) {
                bizBarcodeMapper.batchUpdateDeliveryStatus(
                    barcodeIds.toArray(new Long[0])
                );
            }
        }

        return rows;
    }

    /**
     * 新增送货单批次明细信息
     * 
     * @param bizDeliveryNote 送货单对象
     */
    public void insertBizDeliveryBatch(BizDeliveryNote bizDeliveryNote)
    {
        List<BizDeliveryBatch> bizDeliveryBatchList = bizDeliveryNote.getBizDeliveryBatchList();
        Long deliveryNoteId = bizDeliveryNote.getDeliveryNoteId();
        if (StringUtils.isNotNull(bizDeliveryBatchList))
        {
            List<BizDeliveryBatch> list = new ArrayList<BizDeliveryBatch>();
            for (BizDeliveryBatch bizDeliveryBatch : bizDeliveryBatchList)
            {
                bizDeliveryBatch.setDeliveryNoteId(deliveryNoteId);
                bizDeliveryBatch.setDeliveryNoteNo(bizDeliveryNote.getDeliveryNoteNo());
                if (StringUtils.isEmpty(bizDeliveryBatch.getBatchStatus())) {
                    bizDeliveryBatch.setBatchStatus("PENDING");
                }
                if (bizDeliveryBatch.getCreatedBy() == null) {
                    bizDeliveryBatch.setCreatedBy(SecurityUtils.getUsername());
                }
                if (bizDeliveryBatch.getCreatedTime() == null) {
                    bizDeliveryBatch.setCreatedTime(DateUtils.getNowDate());
                }
                list.add(bizDeliveryBatch);
            }
            if (list.size() > 0)
            {
                bizDeliveryNoteMapper.batchBizDeliveryBatch(list);
            }
        }
    }

    @Transactional
    @Override
    public int updateBizDeliveryNote(BizDeliveryNote bizDeliveryNote)
    {
        // 更新人和更新时间
        bizDeliveryNote.setUpdatedBy(SecurityUtils.getUsername());
        bizDeliveryNote.setUpdatedTime(DateUtils.getNowDate());

        // 重新计算总箱数与总数量，并填充批次元数据
        Long totalBoxes = 0L;
        BigDecimal totalQuantity = BigDecimal.ZERO;
        List<BizDeliveryBatch> bizDeliveryBatchList = bizDeliveryNote.getBizDeliveryBatchList();
        if (StringUtils.isNotNull(bizDeliveryBatchList)) {
            for (BizDeliveryBatch b : bizDeliveryBatchList) {
                if (b.getBatchBoxes() != null) {
                    totalBoxes += b.getBatchBoxes();
                }
                if (b.getBatchQuantity() != null) {
                    totalQuantity = totalQuantity.add(b.getBatchQuantity());
                }
                b.setDeliveryNoteId(bizDeliveryNote.getDeliveryNoteId());
                b.setDeliveryNoteNo(bizDeliveryNote.getDeliveryNoteNo());
                if (StringUtils.isEmpty(b.getBatchStatus())) {
                    b.setBatchStatus("PENDING");
                }
                if (b.getCreatedBy() == null) {
                    b.setCreatedBy(SecurityUtils.getUsername());
                }
                if (b.getCreatedTime() == null) {
                    b.setCreatedTime(DateUtils.getNowDate());
                }
            }
        }
        bizDeliveryNote.setTotalBoxes(totalBoxes);
        bizDeliveryNote.setTotalQuantity(totalQuantity);

        // 更新主表
        int rows = bizDeliveryNoteMapper.updateBizDeliveryNote(bizDeliveryNote);

        // 先删除旧批次，再写入新批次
        bizDeliveryNoteMapper.deleteBizDeliveryBatchByDeliveryNoteId(bizDeliveryNote.getDeliveryNoteId());
        insertBizDeliveryBatch(bizDeliveryNote);

        // 若前端提供了箱码列表，则同步更新箱码关联
        List<BizDeliveryBarcode> barcodeList = bizDeliveryNote.getBizDeliveryBarcodeList();
        if (StringUtils.isNotNull(barcodeList) && !barcodeList.isEmpty()) {
            // 删除旧的箱码关联
            bizDeliveryBarcodeMapper.deleteByDeliveryNoteId(bizDeliveryNote.getDeliveryNoteId());

            // 建立 (batchNo,itemId)->deliveryBatchId 映射
            Map<String, Long> batchKeyToId = new HashMap<>();
            List<BizDeliveryBatch> persistedBatches = bizDeliveryNoteMapper.selectBizDeliveryBatchListByNoteId(bizDeliveryNote.getDeliveryNoteId());
            if (persistedBatches != null) {
                for (BizDeliveryBatch pb : persistedBatches) {
                    String key = (pb.getBatchNo() == null ? "" : pb.getBatchNo()) + "#" + (pb.getItemId() == null ? "" : pb.getItemId());
                    batchKeyToId.put(key, pb.getDeliveryBatchId());
                }
            }

            List<BizDeliveryBarcode> toInsert = new ArrayList<>();
            for (BizDeliveryBarcode src : barcodeList) {
                BizBarcode bc = null;
                if (src.getBarcodeId() != null) {
                    bc = bizBarcodeMapper.selectBizBarcodeByBarcodeId(src.getBarcodeId());
                }
                Long deliveryBatchId = null;
                if (bc != null) {
                    String key = (bc.getBatchNo() == null ? "" : bc.getBatchNo()) + "#" + (bc.getItemId() == null ? "" : bc.getItemId());
                    deliveryBatchId = batchKeyToId.get(key);
                }

                BizDeliveryBarcode item = new BizDeliveryBarcode();
                item.setDeliveryBatchId(deliveryBatchId);
                item.setDeliveryNoteId(bizDeliveryNote.getDeliveryNoteId());
                item.setBarcodeId(src.getBarcodeId());
                item.setBarcode(src.getBarcode());
                item.setInventoryCode(bc != null ? bc.getInventoryCode() : src.getInventoryCode());
                item.setPackQuantity(bc != null ? bc.getPackQuantity() : src.getPackQuantity());
                item.setUnitCode(bc != null ? bc.getUnitCode() : src.getUnitCode());
                item.setBarcodeStatus("PENDING");
                item.setCreateBy(SecurityUtils.getUsername());
                item.setCreateTime(DateUtils.getNowDate());
                toInsert.add(item);
            }

            for (BizDeliveryBarcode item : toInsert) {
                if (item.getDeliveryBatchId() == null) {
                    throw new RuntimeException("箱码与批次匹配失败: barcodeId=" + item.getBarcodeId());
                }
            }

            bizDeliveryBarcodeMapper.batchInsertBizDeliveryBarcode(toInsert);

            // 同步更新主条码状态为 DELIVERED，并写入送货单号与送货时间
            java.util.List<Long> barcodeIds = new java.util.ArrayList<>();
            for (BizDeliveryBarcode item : toInsert) {
                if (item.getBarcodeId() != null) {
                    barcodeIds.add(item.getBarcodeId());
                }
            }
            if (!barcodeIds.isEmpty()) {
                bizBarcodeMapper.batchUpdateDeliveryStatus(
                    barcodeIds.toArray(new Long[0])
                );
            }
        }

        return rows;
    }

    @Transactional
    @Override
    public int deleteBizDeliveryNoteByDeliveryNoteId(Long deliveryNoteId)
    {
        // 先删子表（批次与箱码），再删主表
        bizDeliveryBarcodeMapper.deleteByDeliveryNoteId(deliveryNoteId);
        bizDeliveryNoteMapper.deleteBizDeliveryBatchByDeliveryNoteId(deliveryNoteId);
        return bizDeliveryNoteMapper.deleteBizDeliveryNoteByDeliveryNoteId(deliveryNoteId);
    }

    @Transactional
    @Override
    public int deleteBizDeliveryNoteByDeliveryNoteIds(Long[] deliveryNoteIds)
    {
        // 先删子表（批次与箱码），再删主表
        bizDeliveryBarcodeMapper.deleteByDeliveryNoteIds(deliveryNoteIds);
        bizDeliveryNoteMapper.deleteBizDeliveryBatchByDeliveryNoteIds(deliveryNoteIds);
        return bizDeliveryNoteMapper.deleteBizDeliveryNoteByDeliveryNoteIds(deliveryNoteIds);
    }
}
